#ifndef RAYTRACEPRO_SCENE_H
#define RAYTRACEPRO_SCENE_H

#include "stdafx.h"
#include "MeshGeometry.h"
#include "RenderContext.h"

using namespace GxLibBasic;

namespace RayTracePro
{
	const int BVH_MAX_CHILDREN = 8;

	struct BvhNode
	{
		int Flags;
		int Parent;
		BBox Bounds;
		int Children[BVH_MAX_CHILDREN];
		static const unsigned int Nil = (1<<24)-1;
	};
	struct Bvh
	{
		DeviceList<BvhNode> Nodes;
	};
	
	class Scene
	{
		friend class RayTraceSystem;
	private:
		DeviceList<float> ts;
		RayTraceSystem * system;
		Scene(RayTraceSystem * _system);
	private:
		bool dataInGpu;
		cl::Kernel initBvhTracingKernel, traverseBvhKernel;
		cl::Kernel computeHeadFlagsKernel;
		cl::Kernel compressGroups1Kernel, compressGroups2Kernel;
		void InitBvhTracing_GPU(int size, DeviceList<TraverseResult> & continuation, DeviceList<DifferentialGeometry> & result);	
		void ComputeHeadFlags_GPU(int size, DeviceList<int> & headFlags, DeviceList<TraverseResult> & continuation);
		void CompressGroups_GPU(int size, DeviceList<int> & headFlags, DeviceList<int> & scanHeadFlags, DeviceList<SortGroup> & groups, DeviceList<TraverseResult> & continuation);
	public:
		RefPtr<MeshGeometry> mesh;
		Array<RefPtr<MeshGeometry>> meshes;
		DeviceList<GeometryInstance> Instances;
		RefPtr<Bvh> Bvh;
	public:
		void LoadMesh(const String & fileName);
		void TraceRayPred(DeviceList<int> & result, DeviceList<Ray> & rays);
		void TraceRay_BVH(DeviceList<DifferentialGeometry> & result, 
							 DeviceList<Ray> & rays, 
						 	 DeviceList<RayDifferential> & rayDiffs,
							 DeviceList<TraverseResult> & continuation,
							 DeviceList<int> & headFlags, 
							 DeviceList<int> & scanHeadFlags,
							 DeviceList<SortGroup> & groups,
							 DeviceList<int> & skeleton);
		void TraceRay_BVH_GPU(DeviceList<DifferentialGeometry> & result, 
							  DeviceList<Ray> & rays, 
							  DeviceList<RayDifferential> & rayDiffs,
							  DeviceList<TraverseResult> & continuation,
							  DeviceList<int> & headFlags, 
							  DeviceList<int> & scanHeadFlags,
							  DeviceList<SortGroup> & groups,
							  DeviceList<int> & skeleton,
							  DeviceList<Vec4> & intermediateIntersections);
	};
}

#endif